package com.qidian.by.sso.service.impl;

import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qidian.by.pojo.UserBase;
import com.qidian.by.sso.mapper.UserBaseMapper;
import com.qidian.by.sso.service.IUserBaseService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qidian.by.sso.util.JWTUtil;
import com.qidian.by.util.exceptions.ServiceExceptionEnum;
import com.qidian.by.util.pojo.EsResult;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 小可怎么都睡不够
 * @since 2024-05-16
 */
@Service
public class UserBaseServiceImpl extends ServiceImpl<UserBaseMapper, UserBase> implements IUserBaseService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private UserBaseMapper userBaseMapper;
    @Autowired
    private JWTUtil jwtUtil;
    @Override
    public EsResult reg(UserBase userBase, String codeToken, String code) {
        // 校验验证码
        if(!stringRedisTemplate.hasKey(codeToken)){
            return EsResult.error(ServiceExceptionEnum.VERIFICATION_CODE_HAS_EXPIRED);
        }
        if(!stringRedisTemplate.opsForValue().get(codeToken).equalsIgnoreCase(code)){
            return EsResult.error(ServiceExceptionEnum.VERIFICATION_FAILED);
        }
        // 注册用户
        // 校验用户名是否重复
        QueryWrapper<UserBase> wrapper = new QueryWrapper<>();
        wrapper.eq("username",userBase.getUsername());
        if(userBaseMapper.selectCount(wrapper) > 0){
            return EsResult.error(ServiceExceptionEnum.USERNAME_REPEAT);
        }
        // 注册用户
        // 密码加密
        userBase.setUserPass(DigestUtils.md5Hex(userBase.getUserPass().getBytes()));
        return EsResult.isSuccess(userBaseMapper.insert(userBase));
    }

    @Override
    public EsResult login(UserBase userBase) {
        QueryWrapper<UserBase> wrapper = new QueryWrapper<>();
        wrapper.eq("username",userBase.getUsername());
        UserBase user = userBaseMapper.selectOne(wrapper);
        if(user != null){
            if(user.getUserPass().equals(DigestUtils.md5Hex(userBase.getUserPass().getBytes()))){
                // 生成token
                Map map = new HashMap();
                map.put("userId",user.getUserId().toString());
                map.put("username",user.getUsername());
                map.put("nickname",user.getNickname());
                String token = jwtUtil.getToken(map, 60 * 30);
                // 将token放入redis
                stringRedisTemplate.opsForValue().set(token,user.getUserId().toString());
                // 设置时间为24小时
                stringRedisTemplate.expire(token,24, TimeUnit.HOURS);
                return EsResult.ok("ok",token);
            }
        }
        return EsResult.error(ServiceExceptionEnum.LOGIN_ERROR);
    }

    @Override
    public EsResult checkLogin(String token) {
        if(StringUtils.isNoneBlank(token)){
            try {
                jwtUtil.checkToken(token);
                // 校验通过
                // 获取用户信息
                Map<String, Claim> tokenInfo = jwtUtil.getTokenInfo(token);
                // 理论上这里应该重新生成一次token,防止用户在线的情况下依然token过期
                // 但是我们要实现token续签，所以不需要重新生成
                UserBase userBase = new UserBase();
                userBase.setUserId(Long.parseLong(tokenInfo.get("userId").asString()));
                userBase.setUsername(tokenInfo.get("username").asString());
                userBase.setNickname(tokenInfo.get("nickname") != null ? tokenInfo.get("nickname").asString():"");
                return EsResult.ok(userBase);
            }catch (TokenExpiredException e){
                // token过期
                // 续签
                // 产生新的token，并且将新的token返回
                // 使用新的token替换redis中的原来的token
                // 获取用户的id
                String userIdStr = stringRedisTemplate.opsForValue().get(token);
                if(StringUtils.isBlank(userIdStr)){
                    return EsResult.error();
                }
                Long userId = Long.parseLong(userIdStr);
                // 查询用户信息
                UserBase userBase = userBaseMapper.selectById(userId);
                // 生成新的token
                Map map = new HashMap();
                map.put("userId",userBase.getUserId().toString());
                map.put("username",userBase.getUsername());
                map.put("nickname",userBase.getNickname());
                String newToken = jwtUtil.getToken(map, 60 * 30);
                // 获取原来的token在redis中的时间
                Long expire = stringRedisTemplate.getExpire(token, TimeUnit.SECONDS);
                // 删除原来的token在redis中数据
                stringRedisTemplate.delete(token);
                // 将新的token放入redis
                stringRedisTemplate.opsForValue().set(newToken,userBase.getUserId().toString());
                // 设置时间为获取的时间
                stringRedisTemplate.expire(newToken,expire,TimeUnit.SECONDS);
                // 返回数据，携带新的token
                return EsResult.ok(newToken,map);
            } catch (Exception e) {
                e.printStackTrace();
                return EsResult.error();
            }
        }
        return EsResult.error();
    }
}
